package com.ybt.communicate.ws.client;

import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;

import org.apache.axis2.client.async.AxisCallback;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.rpc.client.RPCServiceClient;
import org.apache.log4j.Logger;

import com.ruleengine.context.IContextProperty;
import com.ruleengine.context.IWorkflowConext;
import com.ybt.communicate.core.IConnection;
import com.ybt.communicate.core.callback.IConnectionCallback;
import com.ybt.communicate.core.exception.ProtocolException;
import com.ybt.communicate.ws.configration.WSConstants;
import com.ybt.communicate.ws.configration.WSRuntimeConfig;
import com.ybt.communicate.ws.configration.WSRuntimeConfig.Parameter;

public class WSClientRPCConnection implements IConnection {
    private static Logger logger = Logger
            .getLogger(WSClientRPCConnection.class);
    private WSRuntimeConfig config;
    private QName opAddEntry;
    private RPCServiceClient serviceClient;

    public WSClientRPCConnection(RPCServiceClient serviceClient,
            WSRuntimeConfig config) {
        super();
        this.serviceClient = serviceClient;
        this.config = config;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ybt.communicate.core.IConnection#receive()
     */
    public Object receive() throws ProtocolException {
        // TODO Auto-generated method stub
        throw new ProtocolException("unsupport method for "
                + config.getProtocolType() + ", protocol id ["
                + config.getProtocolId() + "]");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ybt.communicate.core.IConnection#send(com.ruleengine.context.IWorkflowConext,
     *      java.lang.Object)
     */
    public Object send(IWorkflowConext context, Object data)
            throws ProtocolException {
        try {
            // 解析ws参数
            Object[] opAddEntryArgs = this.prepareData(context,data);
            logger.debug("invoke the ws "
                    + serviceClient.getTargetEPR().getAddress());
            logger.debug(" method : " + opAddEntry.toString());
            logger.debug(" parameter : " + opAddEntryArgs);
            
            //同步调用ws客户端
            return serviceClient.invokeBlocking(opAddEntry, opAddEntryArgs).getFirstElement().getText();
        } catch (Exception e) {
            throw new ProtocolException(e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ybt.communicate.core.IConnection#sendNonBlocking(com.ruleengine.context.IWorkflowConext,
     *      java.lang.Object,
     *      com.ybt.communicate.core.callback.IConnectionCallback)
     */
    public void sendNonBlocking(IWorkflowConext context, Object data,
            final IConnectionCallback callBack) throws ProtocolException {
        // TODO Auto-generated method stub
        try {
            // 解析ws参数
            Object[] opAddEntryArgs = this.prepareData(context, data);
            logger.debug("invokeNonBlocking the ws "
                    + serviceClient.getTargetEPR().getAddress());
            logger.debug(" method : " + opAddEntry.toString());
            logger.debug(" parameter : " + opAddEntryArgs);
            // 异步调用
            serviceClient.invokeNonBlocking(opAddEntry, opAddEntryArgs,
                    new AxisCallback() {
                        public void onComplete() {
                            logger.debug("complete on calling web service to "
                                    + serviceClient.getTargetEPR().getAddress());
                        }

                        public void onError(Exception arg0) {
                            logger.debug("receive the error response from "
                                    + serviceClient.getTargetEPR().getAddress());
                            callBack.onError(arg0);
                        }

                        public void onFault(MessageContext arg0) {
                            logger.debug("receive the fault response from "
                                    + serviceClient.getTargetEPR().getAddress());
                            callBack.onError(arg0.getFailureReason());
                        }

                        public void onMessage(MessageContext mc) {
                            // 调用回调方法，通知客户端ws 已经返回
                            String result = mc.getEnvelope().getFirstElement()
                                    .getFirstElement().getFirstElement()
                                    .getText();
                            logger.debug("receive the response from "
                                    + serviceClient.getTargetEPR().getAddress()
                                    + "[" + result + "]");
                            callBack.onComplete(result);
                        }
                    });
        } catch (Exception e) {
            throw new ProtocolException(e);
        }
    }

    private Object[] prepareData(IWorkflowConext context, Object data)
            throws Exception {
        // 解析ws参数
        List<Object> opAddEntryArgs = new ArrayList<Object>();
        for (Parameter p : config.getParameters()) {
            if (WSConstants.PARAM_TYPE_PROPERTY.equals(p.getType())) {
                // context中获取属性
                IContextProperty pro = context.getContextProperty(p.getValue());
                opAddEntryArgs.add(pro.getValue());
            } else if (WSConstants.PARAM_TYPE_LITERAL.equals(p.getType())) {
                // 固定参数
                opAddEntryArgs.add(p.getValue());
            }else if (WSConstants.PARAM_TYPE_DYNAMIC.equals(p.getType())) {
                // 动态参数
                opAddEntryArgs.add(data);
            } else {
                throw new ProtocolException(
                        "unsupport parameter type of data to client " + p);
            }
        }
        return opAddEntryArgs.toArray();

    }

    public void setOperator(QName opAddEntry) {
        this.opAddEntry = opAddEntry;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ybt.communicate.core.IConnection#close()
     */
    public void close() throws ProtocolException {
        // TODO Auto-generated method stub
    }

    public String getProtocolId() {
        // TODO Auto-generated method stub
        return config.getProtocolType();
    }

}
